'use strict';

/*-------------------------------------------------------------
       _                         
 _   _(_) __ _ _ __ _____      __
| | | | |/ _` | '__/ _ \ \ /\ / /
| |_| | | (_| | | | (_) \ V  V / 
\__ , |_|\__, |_|  \___/ \_/\_/  
 |___/   |___/ (C)2023 shhoo.cn

 1、查询可入网设备
 2、设置入网设备名称及路数
-------------------------------------------------------------*/
import moment from 'moment';
moment.locale('zh-cn');
import { RedisGatewayClass } from "../lib/redis_gateway";
import Mysql from "../lib/mysqlUtil";
import { generateCRC8Code, convert4F2NullOrNum, convert2F2NullOrNum, convertHexNumStrToWantedLengthUppercase } from "../lib/basic"

function mergeRollerGroupStop(RedisGateway: RedisGatewayClass, rollersInfo: any[]) {
    rollersInfo.forEach((roller) => {
        let openSlaver_sn = roller.f_actuator_sn;
        rollerForceStopSlaver(RedisGateway, openSlaver_sn)
    })
}

function mergeRollerGroupCtrl(RedisGateway: RedisGatewayClass, rollersInfo: any[], targetOpen: number) {
    //{"openChName":"DO_E240100B_0_2","openTravel":[10,10,10,10,10,10,10,10,10,10],"forceOpenTime":120,"openCorrection":0,"closeChName":"DO_E240100B_0_4","closeTravel":[10,10,10,10,10,10,10,10,10,10],"forceCloseTime":110,"closeCorrection":0,"errCorrectionCnt":0}
    // console.log(slaverInfo.f_pre_allocate3);
    targetOpen = targetOpen == 240 ? 0 : targetOpen;
    rollersInfo.forEach((roller) => {
        let openSlaver_sn = roller.f_actuator_sn;
        rollerOpenSlaver(RedisGateway, openSlaver_sn, targetOpen)
    })
}
/**
 * 单控卷膜
 * @param RedisGateway 
 * @param openSlaver_sn 
 * @param targetOpen 
 */
function rollerOpenSlaver(RedisGateway: RedisGatewayClass, openSlaver_sn: string, targetOpen: number) {
    //61AF194A0B000100 FEA02107C001000501011F740D0A0D0A0D0A
    targetOpen = targetOpen == 240 ? 0 : targetOpen
    Mysql.QueryConditionalDataFromTable('t_actuator', `f_actuator_sn='${openSlaver_sn}' AND f_actuator_type_id='C001'`).then((info) => {
        if (info.length > 0) {
            let lastOpen = parseInt(info[0].f_last_value);
            lastOpen = isNaN(lastOpen) ? 0 : lastOpen;
            let sn = info[0].f_actuator_sn;
            let addr = info[0].f_actuator_addr;
            let channel = parseInt(info[0].f_channel);
            let zoneId = parseInt(info[0].f_zone_id);
            let f_actuator_alias = info[0].f_actuator_alias;
            let deviceHead = Buffer.from([0x61]);
            let deviceOthers = Buffer.from([0x00, 0x01, 0x00]);
            let frameId = Buffer.from([0xA0, 0x21]);
            let ackFrameBuf = Buffer.concat([Buffer.from([0xfe]), frameId, Buffer.from([0x00]), Buffer.from('C001', 'hex'), Buffer.from('00', 'hex'), Buffer.from([zoneId]), Buffer.from('01', 'hex'), Buffer.from([channel]), Buffer.from([targetOpen]), Buffer.from([0x00, 0xd, 0xa, 0xd, 0xa, 0xd, 0xa])]);
            //console.log(`${new Date().toLocaleString()}`,ackFrameBuf);
            let dataLenth = ackFrameBuf.length - 11;
            ackFrameBuf[3] = dataLenth;
            //console.log(`${new Date().toLocaleString()}`,'dataLenth', ackFrameBuf[3].toString(16).toUpperCase());
            let crc8Buf = ackFrameBuf.slice(4, -7);
            //console.log(`${new Date().toLocaleString()}`,'crc8Buf', crc8Buf.toString('hex').toUpperCase());
            ackFrameBuf[ackFrameBuf.length - 7] = generateCRC8Code(crc8Buf);
            let sendCmd = Buffer.alloc(ackFrameBuf.length + 3);
            sendCmd = Buffer.concat([deviceHead, Buffer.from(addr, 'hex'), deviceOthers, ackFrameBuf]);
            console.log(`${new Date().toLocaleString()}`, '\x1b[0;34m【OPEN_SLAVER】---》', sendCmd.toString('hex').toUpperCase());
            RedisGateway.PubSerialDirectCmd(sendCmd.toString('hex').toUpperCase(), 1);
            Mysql.UpdateParamsIntoTableWhereCondition(`t_actuator`, `f_actuator_sn='${sn}'`, `f_settings_para=${targetOpen}`).then((sta) => {
                console.log(`${new Date().toLocaleString()}`, `更新SN为${sn}S100设置目标开度为${targetOpen}`);

            }).catch((err) => {
                console.log(`${new Date().toLocaleString()}`, err);
            })
        } else {
            // console.log(`${new Date().toLocaleString()}【S100.ts/<rollerOpenSlaver>】设备不存在`)
        }
    })
}
/**
 * 单控卷膜
 * @param RedisGateway 
 * @param openSlaver_sn 
 * @param targetOpen 
 */
function rollerForceStopSlaver(RedisGateway: RedisGatewayClass, openSlaver_sn: string) {
    Mysql.QueryConditionalDataFromTable('t_actuator', `f_actuator_sn='${openSlaver_sn}' AND f_actuator_type_id='C001'`).then((info) => {
        if (info.length > 0) {
            let lastOpen = parseInt(info[0].f_last_value);
            lastOpen = isNaN(lastOpen) ? 0 : lastOpen;
            let addr = info[0].f_actuator_addr;
            let zoneId = parseInt(info[0].f_zone_id);
            let groupId = 1;
            let deviceHead = Buffer.from([0x61]);
            let deviceOthers = Buffer.from([0x00, 0x01, 0x00]);
            let frameId = Buffer.from([0xA0, 0x15]);
            let ackFrameBuf = Buffer.concat([Buffer.from([0xfe]), frameId, Buffer.from([0x00]), Buffer.from('C001', 'hex'), Buffer.from('00', 'hex'), Buffer.from([zoneId]), Buffer.from([groupId]), Buffer.from([1]), Buffer.from([0x00, 0xd, 0xa, 0xd, 0xa, 0xd, 0xa])]);
            //	console.log(`${new Date().toLocaleString()}`,ackFrameBuf);
            let dataLenth = ackFrameBuf.length - 11;
            ackFrameBuf[3] = dataLenth;
            //console.log(`${new Date().toLocaleString()}`,'dataLenth', ackFrameBuf[3].toString(16).toUpperCase());
            let crc8Buf = ackFrameBuf.slice(4, -7);
            //console.log(`${new Date().toLocaleString()}`,'crc8Buf', crc8Buf.toString('hex').toUpperCase());
            ackFrameBuf[ackFrameBuf.length - 7] = generateCRC8Code(crc8Buf);
            let sendCmd = Buffer.alloc(ackFrameBuf.length + 3);
            sendCmd = Buffer.concat([deviceHead, Buffer.from(addr, 'hex'), deviceOthers, ackFrameBuf]);
            console.log(`${new Date().toLocaleString()}`, '\x1b[0;34m【S100 FORCE_STOP】---》', sendCmd.toString('hex').toUpperCase());
            RedisGateway.PubSerialDirectCmd(sendCmd.toString('hex').toUpperCase(), 1);
        } else {
            // console.log(`${new Date().toLocaleString()}【S100.ts/<rollerOpenSlaver>】设备不存在`)
        }
    })
}


// |              | 帧头  |   帧ID   | 数据长度 | 设备类型 | 群发标志位 | 通道  | 校验码 |     帧尾     |
// | :----------: | :---: | :------: | :------: | :------: | :--------: | :---: | :----: | :----------: |
// | 长度（Byte） | 1byte |  2byte   |  1byte   |  2byte   |   1byte    | 1byte | 1byte  |    6byte     |
// | 数据（Hex）  |  FE   | **A018** |    04    |   C001   |     X      |   X   |   X    | 0D0A0D0A0D0A |

// |              | 帧头  |   帧ID   | 数据长度 | 设备类型 | 群发标志位 | 通道  | 开棚总时长 | 关棚总时长 | 校验码 |  帧尾  |
// | :----------: | :---: | :------: | :------: | :------: | :--------: | :---: | :--------: | :--------: | :----: | :----: |
// | 长度（Byte） | 1byte |  2byte   |  1 byte  |  2 byte  |   1 byte   | 1byte |   2byte    |   2byte    | 1 byte | 6 byte |
// | 数据（Hex）  |  FE   | **E018** |    08    |   C001   |     X      |   X   |     XX     |     XX     |   X    | XXXXXX |

var ROLLER_READ_TIME_INTERVAL = {};
var ROLLER_READ_TIME_STATUS_OBJ = {};
function SET_S100_READ_TIME_STATUS_OBJ(key, value) {
    ROLLER_READ_TIME_STATUS_OBJ[key] = value;
}
function S100ReadTotalTime(RedisGateway: RedisGatewayClass, addr: string, channel: number) {
    return new Promise(function (resolve, reject) {
        try {
            let key = `${addr}_${channel.toString().padStart(2, "0")}`;
            if (ROLLER_READ_TIME_INTERVAL[key] != null) {
                clearInterval(ROLLER_READ_TIME_INTERVAL[key]);
                ROLLER_READ_TIME_INTERVAL[key] = null;
            }
            if (typeof (addr) == "string" && addr.length == 8 && typeof (channel) == "number") {
                let ackFrameBuf = Buffer.concat([Buffer.from([0xfe, 0xa0, 0x18, 0x04, 0xC0, 0x01, 0x55, channel]), Buffer.from([0x00, 0xd, 0xa, 0xd, 0xa, 0xd, 0xa])]);
                // console.log(`${new Date().toLocaleString()}`,ackFrameBuf);
                let dataLenth = ackFrameBuf.length - 11;
                ackFrameBuf[3] = dataLenth;
                let crc8Buf = ackFrameBuf.slice(4, -7);
                // console.log(`${new Date().toLocaleString()}`,'crc8Buf-->token:', crc8Buf.toString('hex').toUpperCase());
                ackFrameBuf[ackFrameBuf.length - 7] = generateCRC8Code(crc8Buf);
                let deviceHead = Buffer.from([0x61]);
                let deviceOthers = Buffer.from([0x00, 0x01, 0x00]);
                let sendCmd = Buffer.alloc(ackFrameBuf.length + 3);
                sendCmd = Buffer.concat([deviceHead, Buffer.from(addr, 'hex'), deviceOthers, ackFrameBuf]);
                console.log(`${new Date().toLocaleString()}`, '\x1b[30;34m【S100ReadTotalTime】--->>>', sendCmd.toString('hex').toUpperCase());
                ROLLER_READ_TIME_STATUS_OBJ[`S100ReadTotalTime:${addr}_${channel.toString().padStart(2, "0")}`] = { "value": null, "channel": null, "totalOpenTime": null, "totalCloseTime": null };
                console.log(`S100ReadTotalTime:${addr}_${channel.toString().padStart(2, "0")}`)
                RedisGateway.PubSerialDirectCmd(sendCmd.toString('hex').toUpperCase(), 1);
                let cnt = 0;
                let retryCount = 1;
                let retries = 3;
                ROLLER_READ_TIME_INTERVAL[key] = setInterval(() => {
                    let body = ROLLER_READ_TIME_STATUS_OBJ[`S100ReadTotalTime:${addr}_${channel.toString().padStart(2, "0")}`];
                    // console.log(body)
                    // console.log(`${new Date().toLocaleString()}`,addr, rcvData)
                    if (body.value !== null && body.channel == channel) {
                        let value = body.value;
                        // console.log(`${new Date().toLocaleString()}`,`\x1b[0;32m 【S100ReadTotalTime】(地址：${addr})读取S100控制器行程时间送第【${retryCount}】次指令成功！！`);
                        clearInterval(ROLLER_READ_TIME_INTERVAL[key]);
                        ROLLER_READ_TIME_INTERVAL[key] = null;
                        cnt = 0;
                        console.log(`${new Date().toLocaleString()}`, `\x1b[30;33m【读取S100控制器行程时间成功】地址为：${addr}`)
                        resolve([body.totalOpenTime, body.totalCloseTime]);
                    } else {
                        if (cnt >= 25 * retryCount) {
                            if (retryCount < retries) {
                                RedisGateway.PubSerialDirectCmd(sendCmd.toString('hex').toUpperCase(), 1);
                                console.log(`${new Date().toLocaleString()}`, `\x1b[0;33m 【S100ReadTotalTime】(地址：${addr})读取S100控制器行程时间，重试第【${retryCount}】次！！`)
                                console.log(`${new Date().toLocaleString()}`, `\x1b[104;37m 【S100ReadTotalTime】：\x1b[0;34m--->>>`, sendCmd.toString('hex').toUpperCase(), moment().format('YYYY-MM-DD HH:mm:ss'));
                                retryCount++;
                            } else {
                                console.log(`${new Date().toLocaleString()}`, `\x1b[0;31m【S100ReadTotalTime】(地址：${addr})读取S100控制器行程时间，重试【${retries}】次失败！！`);
                                reject(`请检查S100控制器供电和通讯是否正常！！`);
                                clearInterval(ROLLER_READ_TIME_INTERVAL[key]);
                                ROLLER_READ_TIME_INTERVAL[key] = null;
                            }
                            cnt = 0;
                        }
                        cnt++;
                    }
                }, 100)

            } else {
                // console.log(`${new Date().toLocaleString()}`,'\x1b[0;31m[S100ReadTotalTime]数据错误！！')
                reject('[S100ReadTotalTime]数据错误！！')
            }
        } catch (error) {
            console.log(`${new Date().toLocaleString()}`, error)
            reject(error)
        }
    })

}

// |              | 帧头  |   帧ID   | 数据长度 | 设备类型 | 群发标志位 | 通道  | 开棚总时长 | 关棚总时长 | 校验码 |     帧尾     |
// | :----------: | :---: | :------: | :------: | :------: | :--------: | :---: | :--------: | :--------: | :----: | :----------: |
// | 长度（Byte） | 1byte |  2byte   |  1byte   |  2byte   |   1byte    | 1byte |   2byte    |   2byte    | 1byte  |    6byte     |
// | 数据（Hex）  |  FE   | **A017** |    08    |   C001   |     X      |   X   |     XX     |     XX     |   X    | 0D0A0D0A0D0A |

// |              | 帧头  |   帧ID   | 数据长度 | 设备类型 | 群发标志位 | 通道  | 开棚总时长 | 关棚总时长 | 回执状态码 | 校验码 |  帧尾  |
// | :----------: | :---: | :------: | :------: | :------: | :--------: | :---: | :--------: | :--------: | :--------: | :----: | :----: |
// | 长度（Byte） | 1byte |  2byte   |  1 byte  |  2 byte  |   1 byte   | 1byte |   2byte    |   2byte    |   1 byte   | 1 byte | 6 byte |
// | 数据（Hex）  |  FE   | **E017** |    09    |   C001   |     X      |   X   |     XX     |     XX     |     X      |   X    | XXXXXX |

var ROLLER_SET_TIME_INTERVAL = {};
var ROLLER_SET_TIME_STATUS_OBJ = {};
function SET_S100_SET_TIME_STATUS_OBJ(key, value) {
    ROLLER_SET_TIME_STATUS_OBJ[key] = value;
}

function S100SetTotalTime(RedisGateway: RedisGatewayClass, addr: string, channel: number, totalOpenTime: number, totalCloseTime: number): Promise<[number, number]> {
    return new Promise(function (resolve, reject) {
        try {
            let key = `${addr}_${channel.toString().padStart(2, "0")}`;
            if (ROLLER_SET_TIME_INTERVAL[key] != null) {
                clearInterval(ROLLER_SET_TIME_INTERVAL[key]);
                ROLLER_SET_TIME_INTERVAL[key] = null;
            }

            if (typeof (addr) == "string" && addr.length == 8 && typeof (channel) == "number" && typeof (totalOpenTime) == "number" && typeof (totalCloseTime) == "number") {
                let ackFrameBuf = Buffer.concat([Buffer.from([0xfe, 0xa0, 0x17, 0x08, 0xC0, 0x01, 0x55, channel]), Buffer.from(totalOpenTime.toString(16).padStart(4, '0'), 'hex'), Buffer.from(totalCloseTime.toString(16).padStart(4, '0'), 'hex'), Buffer.from([0x00, 0xd, 0xa, 0xd, 0xa, 0xd, 0xa])]);
                // console.log(`${new Date().toLocaleString()}`,ackFrameBuf);
                let dataLenth = ackFrameBuf.length - 11;
                ackFrameBuf[3] = dataLenth;
                let crc8Buf = ackFrameBuf.slice(4, -7);
                // console.log(`${new Date().toLocaleString()}`,'crc8Buf-->token:', crc8Buf.toString('hex').toUpperCase());
                ackFrameBuf[ackFrameBuf.length - 7] = generateCRC8Code(crc8Buf);
                let cmdPacket = Buffer.alloc(ackFrameBuf.length + 3);
                cmdPacket = Buffer.concat([Buffer.from(addr, 'hex'), ackFrameBuf]);
                let deviceHead = Buffer.from([0x61]);
                let deviceOthers = Buffer.from([0x00, 0x01, 0x00]);
                let sendCmd = Buffer.alloc(ackFrameBuf.length + 3);
                sendCmd = Buffer.concat([deviceHead, Buffer.from(addr, 'hex'), deviceOthers, ackFrameBuf]);
                console.log(`${new Date().toLocaleString()}`, '\x1b[30;34m【S100SetTotalTime】--->>>', sendCmd.toString('hex').toUpperCase());
                ROLLER_SET_TIME_STATUS_OBJ[`S100SetTotalTime:${addr}_${channel.toString().padStart(2, "0")}`] = { "value": null, "channel": null, "totalOpenTime": null, "totalCloseTime": null };
                console.log(`S100SetTotalTime:${addr}_${channel.toString().padStart(2, "0")}`)
                RedisGateway.PubSerialDirectCmd(sendCmd.toString('hex').toUpperCase(), 1);
                let cnt = 0;
                let retryCount = 1;
                let retries = 3;
                ROLLER_SET_TIME_INTERVAL[key] = setInterval(() => {
                    let body = ROLLER_SET_TIME_STATUS_OBJ[`S100SetTotalTime:${addr}_${channel.toString().padStart(2, "0")}`];
                    // console.log(body)
                    // console.log(`${new Date().toLocaleString()}`,addr, rcvData)
                    if (body.value !== null && body.channel == channel) {
                        let value = body.value;
                        // console.log(`${new Date().toLocaleString()}`,`\x1b[0;32m 【S100SetTotalTime】(地址：${addr})设定S100控制器行程时间送第【${retryCount}】次指令成功！！`);
                        clearInterval(ROLLER_SET_TIME_INTERVAL[key]);
                        ROLLER_SET_TIME_INTERVAL[key] = null;
                        cnt = 0;
                        console.log(`${new Date().toLocaleString()}`, `\x1b[30;33m【设定S100控制器行程时间成功】地址为：${addr}`)
                        resolve([body.totalOpenTime, body.totalCloseTime]);
                    } else {
                        if (cnt >= 25 * retryCount) {
                            if (retryCount < retries) {
                                RedisGateway.PubSerialDirectCmd(sendCmd.toString('hex').toUpperCase(), 1);
                                console.log(`${new Date().toLocaleString()}`, `\x1b[0;33m 【S100SetTotalTime】(地址：${addr})设定S100控制器行程时间，重试第【${retryCount}】次！！`)
                                console.log(`${new Date().toLocaleString()}`, `\x1b[104;37m 【S100SetTotalTime】：\x1b[0;34m--->>>`, cmdPacket.toString('hex').toUpperCase(), moment().format('YYYY-MM-DD HH:mm:ss'));
                                retryCount++;
                            } else {
                                console.log(`${new Date().toLocaleString()}`, `\x1b[0;31m【S100SetTotalTime】(地址：${addr})设定S100控制器行程时间，重试【${retries}】次失败！！`);
                                reject(`请检查S100控制器供电和通讯是否正常！！`);
                                clearInterval(ROLLER_SET_TIME_INTERVAL[key]);
                                ROLLER_SET_TIME_INTERVAL[key] = null;
                            }
                            cnt = 0;
                        }
                        cnt++;
                    }
                }, 100)
            } else {
                // console.log(`${new Date().toLocaleString()}`,'\x1b[0;31m[S100SetTotalTime]数据错误！！')
                reject('[S100SetTotalTime]数据错误！！')
            }
        } catch (error) {
            console.log(`${new Date().toLocaleString()}`, error)
            reject(error)
        }
    })

}
/**
 * (A013)设置设备SN及设备路数,默认区域1工作组数组（0100000000）
 * @param {string} deviceAddr      设备地址
 * @param {string} deviceTypeId    设备类型id
 * @param {string} zoneId          区域ID
 * @param {string} channel         设备路数
 * @param {string} newdeviceSn     设置SN
 */
function setActuatorDeviceSnAndChannel(RedisGateway: RedisGatewayClass, deviceAddr: string, deviceTypeId: string, zoneId: number, channel: number, newdeviceSn: string) {
    let slaverCount = 1;
    console.log(`${new Date().toLocaleString()}`, deviceAddr, deviceTypeId, zoneId, channel, newdeviceSn, slaverCount)
    let deviceHead = Buffer.from([0x61]);
    let deviceOthers = Buffer.from([0x00, 0x01, 0x00]);
    let frameId = Buffer.from([0xA0, 0x13]);
    let addr = deviceAddr;
    let isBroadCast = '55';
    if (addr !== "00000071") {
        isBroadCast = '00';
    }
    console.log(`${new Date().toLocaleString()}`, "addr", addr);
    //FE A013 0C C001 00 C00120190304150001 EC 0D0A0D0A0D0A
    let ackFrameBuf = Buffer.concat([Buffer.from([0xfe]), frameId, Buffer.from([0x00]), Buffer.from(deviceTypeId, 'hex'), Buffer.from(isBroadCast, 'hex'), Buffer.from([zoneId]), Buffer.from([channel]), Buffer.from([slaverCount]), Buffer.from(newdeviceSn, 'hex'), Buffer.from([0x00, 0xd, 0xa, 0xd, 0xa, 0xd, 0xa])]);
    let dataLenth = ackFrameBuf.length - 11;
    ackFrameBuf[3] = dataLenth;
    console.log(`${new Date().toLocaleString()}`, 'dataLenth', ackFrameBuf[3].toString(16).toUpperCase());
    let crc8Buf = ackFrameBuf.slice(4, -7);
    console.log(`${new Date().toLocaleString()}`, 'crc8Buf', crc8Buf.toString('hex').toUpperCase());
    ackFrameBuf[ackFrameBuf.length - 7] = generateCRC8Code(crc8Buf);
    let sendCmd = Buffer.alloc(ackFrameBuf.length + 3);
    sendCmd = Buffer.concat([deviceHead, Buffer.from(addr, 'hex'), deviceOthers, ackFrameBuf]);
    console.log(`${new Date().toLocaleString()}`, 'sendcmd', sendCmd.toString('hex').toUpperCase());
    RedisGateway.PubSerialDirectCmd(sendCmd.toString('hex').toUpperCase(), 1);
    let params = `f_actuator_status='设置SN及子设备路数成功',f_actuator_sn='${newdeviceSn}',f_zone_id=${zoneId}`
    Mysql.UpdateParamsIntoTable('t_actuator', `f_actuator_addr`, `'${deviceAddr}'`, params).then(() => {
        console.log(`${new Date().toLocaleString()}`, "设置SN更新执行器状态及sn成功！")
    }).catch((err) => {
        console.log(`${new Date().toLocaleString()}`, "设置SN更新执行器状态及sn发送错误：", err);
    })
}
/**
 * (A014)查询当前设备设置实时运行状态
 * @param {string} sendAddr 发送地址
 * @param {string} deviceTypeId 设备类型Id
 * @param {string} zoneId 区域Id
 * @param {string} channel 路数
 */
function queryCurrentRealtimeWorkingStatus(RedisGateway: RedisGatewayClass, sendAddr: string, deviceTypeId: string, zoneId: number, channel: number, qryId: string) {
    try {
        if (deviceTypeId === 'C001') {//61 14432A0C 000100 FE A014 04 C001 01 00 E1 0D0A0D0A0D0A
            let deviceHead = Buffer.from([0x61]);
            let deviceOthers = Buffer.from([0x00, 0x01, 0x00]);
            let frameId = Buffer.from([0xA0, 0x14]);
            let addr = sendAddr;
            let broadCast = '00';
            let ackFrameBuf = Buffer.concat([Buffer.from([0xfe]), frameId, Buffer.from([0x00]), Buffer.from(deviceTypeId, 'hex'), Buffer.from(broadCast, 'hex'), Buffer.from([zoneId]), Buffer.from('55', 'hex'), Buffer.from([0x00, 0xd, 0xa, 0xd, 0xa, 0xd, 0xa])]);
            //6100000071000100 FE A014 05 C001 55 01 55 8D 0D0A0D0A0D0A
            let dataLenth = ackFrameBuf.length - 11;
            ackFrameBuf[3] = dataLenth;
            //console.log(`${new Date().toLocaleString()}`,'dataLenth', ackFrameBuf[3].toString(16).toUpperCase());
            let crc8Buf = ackFrameBuf.slice(4, -7);
            //console.log(`${new Date().toLocaleString()}`,'crc8Buf', crc8Buf.toString('hex').toUpperCase());
            ackFrameBuf[ackFrameBuf.length - 7] = generateCRC8Code(crc8Buf);
            let sendCmd = Buffer.alloc(ackFrameBuf.length + 3);
            sendCmd = Buffer.concat([deviceHead, Buffer.from(addr, 'hex'), deviceOthers, ackFrameBuf]);
            console.log(`${new Date().toLocaleString()}`, '\x1b[0;34m【QueryCurrentRealtimeWorkingStatus】', sendCmd.toString('hex').toUpperCase());
            RedisGateway.PubSerialDirectCmd(sendCmd.toString('hex').toUpperCase(), 1);
        }
    } catch (error) {
        console.log(`${new Date().toLocaleString()}`, `[QueryCurrentDeviceParams]: ${error.toString()}`);
    }
}
function Parser(RedisGateway: RedisGatewayClass, confTyp: string, method: string, qryId: string, para: any | any[]) {
    console.log(para)
    switch (method) {
        case "SET_SN_COUNT"://设置SN
            let setSnDeviceType = para.deviceType;
            if (setSnDeviceType == 'LoRa_Roller') {
                let setSnDeviceAddr = para.deviceAddr;
                let channel = para.channel;
                let zoneId = parseInt(para.zoneId);
                let newdeviceSn = para.newdeviceSn;
                setActuatorDeviceSnAndChannel(RedisGateway, setSnDeviceAddr, 'C001', zoneId, channel, newdeviceSn);
            }
            break;
        case "RESET_SLAVER":

            break;
        case "LIMIT_SLAVER":

            break;

        case "READ_TOTAL_TIME":
            S100ReadTotalTime(RedisGateway, para.addr, para.channel).then(([totalOpenTime, totalCloseTime]) => {
                para.totalOpenTime = totalOpenTime;
                para.totalCloseTime = totalCloseTime;
                console.log(`\x1b[0;32m${new Date().toLocaleString()}【READ_TOTAL_TIME】地址为:${para.addr}读取行程时间，开启时间：${totalOpenTime}S,关闭时间：${totalCloseTime}S\x1b[0;37m`);
                RedisGateway.pubActuatorCmdAck('ROLLER', method, qryId, 'success', `读取行程时间成功`, para);
            }).catch((err) => {
                console.log(err)
                RedisGateway.pubActuatorCmdAck('ROLLER', method, qryId, 'failure', err, para);
            })
            break;
        case 'SET_TOTAL_TIME'://设定总行程时间
            S100SetTotalTime(RedisGateway, para.addr, para.channel, para.totalOpenTime, para.totalCloseTime).then(([totalOpenTime, totalCloseTime]) => {
                console.log(`\x1b[0;32m${new Date().toLocaleString()}【SET_TOTAL_TIME】地址为:${para.addr}设定行程时间，开启时间：${totalOpenTime}S,关闭时间：${totalCloseTime}S成功\x1b[0;37m`);
                RedisGateway.pubActuatorCmdAck('ROLLER', method, qryId, 'success', `设定行程时间成功`, para);
            }).catch((err) => {
                console.log(err)
                RedisGateway.pubActuatorCmdAck('ROLLER', method, qryId, 'failure', `不存在编辑卷膜的'${method}'方法`, para);
            })
            break;
        case "QUERY_STATUS":// {"confTyp":"LORA_COMMON_CMD","method":"QUERY_STATUS","qryId":"111111111111676453731927","para":{"zoneId":1,"deviceType":"LoRa_Roller","groupId":2,"deviceSn":["B00120230215162804"]}}
            if (para.deviceType == "LoRa_Roller") {
                let deviceSnArray = para.deviceSn;
                let groupId = parseInt(para.groupId);
                let zoneId = parseInt(para.zoneId);
                deviceSnArray.forEach((dsn) => {
                    Mysql.SelectLastOneParams("t_actuator", `f_actuator_type='LoRa_Roller' AND f_actuator_sn='${dsn}'`, 'id').then((param) => {
                        let addr = param[0].f_actuator_addr;
                        queryCurrentRealtimeWorkingStatus(RedisGateway, addr, 'C001', zoneId, groupId, qryId);
                    }).catch((err) => {

                    })
                })

            }
            break;
        case "OPEN_SLAVER"://"sn":["B00120230207170620"],"open":[23]
            console.log('S100卷膜控制')
            let s_sn = para.sn;
            let s_open = parseInt(para.open[0]);
            if (s_sn.length > 1) {
                Mysql.QueryConditionalDataFromTable(`t_actuator`, `f_actuator_type_id='C001'`).then((params) => {
                    console.log(params)
                    let groupParams: any[] = [];
                    for (let i = 0; i < params.length; i++) {
                        let index = s_sn.findIndex((sn) => {
                            return sn == params[i].f_actuator_sn;
                        })
                        if (index != -1) {
                            groupParams.push(params[i])
                        }
                    }
                    if (groupParams.length > 0) {
                        let len = groupParams.length;
                        let addrs = new Set();
                        let cnt = 0;
                        groupParams.forEach(slaver => {
                            addrs.add(slaver.f_actuator_addr);
                        })
                        addrs.forEach((addr) => {
                            // console.log(addr);
                            let mergerParams: any[] = [];
                            for (let count = 0; count < len; count++) {
                                let index = groupParams.findIndex((device) => {
                                    return device.f_actuator_addr == addr;
                                })
                                if (index != -1) {
                                    mergerParams.push(groupParams[index]);
                                    groupParams.splice(index, 1);
                                }
                                if (count == len - 1) {
                                    setTimeout(() => {
                                        console.log(mergerParams)
                                        mergeRollerGroupCtrl(RedisGateway, mergerParams, s_open);
                                    }, cnt * 100)
                                }
                            }
                            cnt++;
                        })
                    }
                })
            } else {
                rollerOpenSlaver(RedisGateway, s_sn[0], s_open)
            }

            break;
        case "FORCE_STOP"://{"zoneId":1,"groupId":2,"deviceType":"LoRa_Roller","sn":["B00120230207181500"]}
            if (para.deviceType == "LoRa_Roller") {
                let f_zoneId = para.zoneId;
                let f_groupId = para.groupId;
                let f_sn = para.sn;
                if (f_sn[0] == '555555555555555555') {
                    Mysql.QueryConditionalDataFromTable('t_actuator_group', `f_zone_id=${f_zoneId} AND f_group_id=${f_groupId} AND f_actuator_type="LoRa_Roller"`).then((params) => {
                        if (params.length > 0) {
                            // console.log(params)
                            let f_snArr = JSON.parse(params[0].f_actuator_sn_array);
                            Mysql.QueryConditionalDataFromTable(`t_actuator`, `f_zone_id=${f_zoneId} AND f_actuator_type_id='C001'`).then((params1) => {
                                if (params1.length > 0) {
                                    let groupParams: any[] = [];
                                    for (let i = 0; i < params1.length; i++) {
                                        let index = f_snArr.findIndex((sn) => {
                                            return sn == params1[i].f_actuator_sn || sn == "555555555555555555";
                                        })
                                        if (index != -1) {
                                            groupParams.push(params1[i])
                                        }
                                    }
                                    if (groupParams.length > 0) {
                                        let len = groupParams.length;
                                        let addrs = new Set();
                                        let cnt = 0;
                                        groupParams.forEach(slaver => {
                                            addrs.add(slaver.f_actuator_addr);
                                        })
                                        addrs.forEach((addr) => {
                                            // console.log(addr);
                                            let mergerParams: any[] = [];
                                            for (let count = 0; count < len; count++) {
                                                let index = groupParams.findIndex((device) => {
                                                    return device.f_actuator_addr == addr;
                                                })
                                                if (index != -1) {
                                                    mergerParams.push(groupParams[index]);
                                                    groupParams.splice(index, 1);
                                                }
                                                if (count == len - 1) {
                                                    setTimeout(() => {
                                                        // console.log(`S100.ts<Parser>`,mergerParams)
                                                        mergeRollerGroupStop(RedisGateway, mergerParams);
                                                    }, cnt * 100)
                                                }
                                            }
                                            cnt++;
                                        })
                                    }
                                }
                            })
                        }
                    })

                } else {
                    Mysql.QueryConditionalDataFromTable(`t_actuator`, `f_actuator_type_id='C001'`).then((params) => {
                        let groupParams: any[] = [];
                        for (let i = 0; i < params.length; i++) {
                            let index = f_sn.findIndex((sn) => {
                                return sn == params[i].f_actuator_sn;
                            })
                            if (index != -1) {
                                groupParams.push(params[i])
                            }
                        }
                        if (groupParams.length > 0) {
                            let len = groupParams.length;
                            let addrs = new Set();
                            let cnt = 0;
                            groupParams.forEach(slaver => {
                                addrs.add(slaver.f_actuator_addr);
                            })
                            addrs.forEach((addr) => {
                                // console.log(addr);
                                let mergerParams: any[] = [];
                                for (let count = 0; count < len; count++) {
                                    let index = groupParams.findIndex((device) => {
                                        return device.f_actuator_addr == addr;
                                    })
                                    if (index != -1) {
                                        mergerParams.push(groupParams[index]);
                                        groupParams.splice(index, 1);
                                    }
                                    if (count == len - 1) {
                                        setTimeout(() => {
                                            // console.log(mergerParams)
                                            mergeRollerGroupStop(RedisGateway, mergerParams);
                                        }, cnt * 100)
                                    }
                                }
                                cnt++;
                            })
                        }
                    })
                }


            }

            break;
        case "OPEN_GROUP"://{"zoneId":1,"groupId":[2],"open":[0]}}
            let g_zoneId = para.zoneId;
            let g_groupId = para.groupId[0];
            let g_open = parseInt(para.open[0]);
            let g_sn = para.sn == undefined ? ["555555555555555555"] : para.sn;
            console.log(g_sn)
            if (g_sn[0] == '555555555555555555') {
                Mysql.QueryConditionalDataFromTable('t_actuator_group', `f_zone_id=${g_zoneId} AND f_group_id=${g_groupId} AND f_actuator_type="LoRa_Roller"`).then((params) => {
                    if (params.length > 0) {
                        let g_snArr = JSON.parse(params[0].f_actuator_sn_array);
                        console.log(g_snArr)
                        Mysql.QueryConditionalDataFromTable(`t_actuator`, `f_zone_id=${g_zoneId} AND f_actuator_type_id='C001'`).then((params1) => {
                            if (params1.length > 0) {
                                let groupParams: any[] = [];
                                for (let i = 0; i < params1.length; i++) {
                                    let index = g_snArr.findIndex((sn) => {
                                        return sn == params1[i].f_actuator_sn || sn == "555555555555555555";
                                    })
                                    if (index != -1) {
                                        groupParams.push(params1[i])
                                    }
                                }
                                if (groupParams.length > 0) {
                                    let len = groupParams.length;
                                    let addrs = new Set();
                                    let cnt = 0;
                                    groupParams.forEach(slaver => {
                                        addrs.add(slaver.f_actuator_addr);
                                    })
                                    addrs.forEach((addr) => {
                                        // console.log(addr);
                                        let mergerParams: any[] = [];
                                        for (let count = 0; count < len; count++) {
                                            let index = groupParams.findIndex((device) => {
                                                return device.f_actuator_addr == addr;
                                            })
                                            if (index != -1) {
                                                mergerParams.push(groupParams[index]);
                                                groupParams.splice(index, 1);
                                            }
                                            if (count == len - 1) {
                                                setTimeout(() => {
                                                    // console.log(mergerParams)
                                                    mergeRollerGroupCtrl(RedisGateway, mergerParams, g_open);
                                                }, cnt * 100)
                                            }
                                        }
                                        cnt++;
                                    })
                                }
                            }
                        })


                    }
                })
            } else {
                Mysql.QueryConditionalDataFromTable(`t_actuator`, `f_actuator_type_id='C001'`).then((params) => {
                    let groupParams: any[] = [];
                    for (let i = 0; i < params.length; i++) {
                        let index = g_sn.findIndex((sn) => {
                            return sn == params[i].f_actuator_sn;
                        })
                        if (index != -1) {
                            groupParams.push(params[i])
                        }
                    }
                    if (groupParams.length > 0) {
                        let len = groupParams.length;
                        let addrs = new Set();
                        let cnt = 0;
                        groupParams.forEach(slaver => {
                            addrs.add(slaver.f_actuator_addr);
                        })
                        addrs.forEach((addr) => {
                            // console.log(addr);
                            let mergerParams: any[] = [];
                            for (let count = 0; count < len; count++) {
                                let index = groupParams.findIndex((device) => {
                                    return device.f_actuator_addr == addr;
                                })
                                if (index != -1) {
                                    mergerParams.push(groupParams[index]);
                                    groupParams.splice(index, 1);
                                }
                                if (count == len - 1) {
                                    setTimeout(() => {
                                        // console.log(mergerParams)
                                        mergeRollerGroupCtrl(RedisGateway, mergerParams, g_open);
                                    }, cnt * 100)
                                }
                            }
                            cnt++;
                        })
                    }
                })
            }

            break;
        default:
            break;
    }
}
function CommonAckStatusParser(RedisGateway: RedisGatewayClass, addr: string, freameData: Buffer) {
    // |   字节索引   |     0     |  1\|2   |    3    |     4\|5     | 6     |  7     |   8    |      8-15        |  16   |       17-22      |
    // |    数据域    | FrameHead | FrameId | DataLen | DeviceTypeId |ZoneId|  channel | status |     Allocate     | CRC8  |     FrameEnd      |
    //                  FE         E015      0D        C001            01        00       03      0000000000000000A5
    const commandAck = [
        "出厂模式",
        "查询LoRa设备参数成功",
        "查询LoRa设备参数失败",
        "设置组Id数组成功",
        "设置组Id数组失败",
        "设置SN及子设备路数成功",
        "设置SN及子设备路数失败",
        "强制停止设备成功",
        "强制停止设备失败",
        "重置设备行程成功",
        "重置设备行程失败",
        "设置子设备开度成功",
        "设置子设备开度失败",
        "设置子设备阈值成功",
        "设置子设备阈值失败",
        "设置网关模式成功"
    ]
    let zoneId = parseInt(freameData.slice(7, 8).toString('hex'), 16).toString();
    let channel = parseInt(freameData.slice(8, 9).toString('hex'), 16).toString();
    let statusId = freameData.slice(9, 10).toString('hex').toUpperCase();
    let lsnr = convert2F2NullOrNum(freameData.slice(10, 11).toString('hex'));
    let rssi = convert2F2NullOrNum(freameData.slice(11, 12).toString('hex'));
    let allocate = convertHexNumStrToWantedLengthUppercase(freameData.slice(12, 20).toString('hex').toUpperCase(), 16) + '0000000000000000';
    let status = commandAck[parseInt(statusId, 16)];
    //如果设置Sn成功
      Mysql.QueryConditionalDataFromTable("t_actuator", `f_actuator_addr='${addr.toUpperCase()}'`).then((params) => {
        if (params.length > 0) {
            let sn = params[0].f_actuator_sn;
            let f_actuator_alias = params[0].f_actuator_alias;
            let openRate = parseInt(params[0].f_last_value);
            let actuatorData = {
                "addr": addr,
                "channel": channel,
                "status": status,
                "allocate": allocate,
                "lsnr": lsnr,
                "vol": 24000,
                "rssi": rssi,
                "t": moment().format('YYYY-MM-DD HH:mm:ss')
            }
            // console.log(actuatorData)
            updateRollerLastValue(sn, openRate, status, allocate);
            console.log(new Date().toLocaleString(), "\x1b[30;32m【S100.ts/<CommonAckStatusParser>】[通用回执]<------区域：" + zoneId + "的LoRa设备：" + addr + '通道：' + channel + "," + status + ' (' + statusId + ')' + "\x1b[30;37m")
            RedisGateway.pubActuatorCmdAck('ROLLER', 'LORA_COMMON_ACK', `11111111111${moment().unix()}`, 'success', "[通用回执]<------区域：" + zoneId + "的LoRa设备：" + addr + '通道：' + channel + "," + status + ' (' + statusId + ')', [actuatorData]);

        }
    })

}
//                   0       1-2        3        4-5            6          7        8           9        10-11    12      13     14        15-16      17-18     19-20        21          22
// |              | 帧头  |   帧ID    | 数据长度  | 设备类型  | 群发标志位   | 区域号  | 设备路数  | 设备状态   | 电压  |  SNR  | RSSI  | 实时开度   | 最小电流  | 最大电流  | 电流   | 上报频率  | 网络模式   | 软件版本  | 硬件版本   | 预留位 | 符号位   | 校验码  |     帧尾     |
// | 长度（Byte）  | 1byte |  2byte   |  1byte   |  2byte   |   1byte    | 1byte  |  1byte   |  1byte   | 2byte | 1byte | 1byte |  1byte   |  2byte   |  2byte   | 2byte |  1byte   |  1byte   |  1byte   |  1byte   | 5byte  | 2byte  | 1byte  |    6 byte    |
// | 数据（Hex）   |  FE   |   E014   |    1C    |   C001   |     X      |   X    |    X     |    X     |  XX   |   X   |   X   |    X     |    XX    |    XX    |  XX   |    X     |    X     |    X     |    X     | XXXXX  |   XX   |   X    | 0D0A0D0A0D0A |
//                 FE        E014        1C        C001        55         06        01         01       0008      0A      47       64       00FA        0045      0030      1E         F1         1C        59       006A006700E0F0A5
/**
 * 
 * @param RedisGateway 
 * @param addr 
 * @param glsnr 
 * @param grssi 
 * @param freameData 
 */
function WorkingStatusParser(RedisGateway: RedisGatewayClass, addr: string, glsnr: number, grssi: number, freameData: Buffer) {
    // FE E014 1C C001 00 2A 01 0B 0000 05 4A 0000140014001003F014530000000000 E0F0 8C
    //执行器设备请求设置Sn
    //FE E014 1C C001 55 04 01 0100 3E0A56 64 00D2003C00611EF11C590075007100E0F02C
    //0  1-2  3  4-5  6  7  8  9-10 11
    //FE E014 1C C001 55 06 01 0100 080A47 64 00FA004500301EF11C59006A006700E0F0A5
    let statusDoc = [
        "出厂模式",
        "卷膜完成",
        "上限位异常",
        "下限位异常",
        "低电压异常",
        "电机异常",
        "卷膜电流异常",
        "正在卷膜",
        "指令异常",
        "未初始化",
        "数据储存异常",
        "正在重置行程",
        "重置行程完成",
        "485模块异常",
        "强制停止设备成功",
        "手动卷膜完成",
        "手动按键异常",
        "开度错误"
    ];
    // console.log(`${new Date().toLocaleString()}`, `${addr.toUpperCase()}:<--------------${freameData.toString('hex').toUpperCase()}`);
    let dataLenth = parseInt(freameData.slice(3, 4).toString('hex').toUpperCase(), 16);
    // console.log(`${new Date().toLocaleString()}`,freameData.length,dataLenth);
    if (freameData.length - 5 == dataLenth) {
        let zoneId = freameData.slice(7, 8)[0];
        let channel = freameData.slice(8, 9)[0];
        let staId = freameData.slice(9, 10)[0];
        let vol = convert4F2NullOrNum(freameData.slice(10, 12).toString('hex'));
        let lsnr = convert2F2NullOrNum(freameData.slice(12, 13).toString('hex'));
        let rssi = convert2F2NullOrNum(freameData.slice(13, 14).toString('hex'));
        let openRate = freameData.slice(14, 15)[0];
        let lsnrSymbol = freameData.slice(30, 31).toString('hex').toUpperCase();
        let rssiSymbol = freameData.slice(31, 32).toString('hex').toUpperCase();
        let allocate = `${(openRate == 241 ? 100 : openRate == 240 ? 0 : openRate).toString(16).padStart(2, '0')}${freameData.slice(15, 29).toString('hex').toUpperCase()}`;
        let mode = freameData.slice(22, 23).toString('hex').toUpperCase() == `F1` ? `Gateway` : `Node`;
        let swVer = parseInt(freameData.slice(23, 24).toString('hex').toUpperCase(), 16);
        let hwVer = parseInt(freameData.slice(24, 25).toString('hex').toUpperCase(), 16);
        let status = statusDoc[staId];
        let currentTime = moment().format('YYYY-MM-DD HH:mm:ss');
        Mysql.QueryConditionalDataFromTable("t_actuator", `f_actuator_addr='${addr.toUpperCase()}'`).then((params) => {
            if (params.length > 0) {
                let sn = params[0].f_actuator_sn;
                let f_actuator_alias = params[0].f_actuator_alias;
                let actuatorData = {
                    "addr": addr,
                    "channel": channel,
                    "status": status,
                    "allocate": allocate,
                    "glsnr": glsnr,
                    "grssi": grssi,
                    "lsnr": lsnrSymbol == 'F0' ? `-${lsnr}` : `${lsnr}`,
                    "rssi": rssiSymbol == 'F0' ? `-${rssi}` : `${rssi}`,
                    "vol": vol,
                    "t": currentTime
                }
                // console.log(actuatorData)
                updateRollerLastValue(sn, openRate, status, allocate);
                console.log(new Date().toLocaleString(), "\x1b[30;32m【S100.ts/<WorkingStatusParser>】[实时状态]区域:" + zoneId + ",地址:" + addr + "(" + f_actuator_alias + `开度：${openRate}%,` + "实时状态为：" + status + ' (' + staId + ') allocate： ' + allocate + "\x1b[30;37m")
                RedisGateway.pubActuatorCmdAck('ROLLER', 'QUERY_STATUS', `11111111111${moment().unix()}`, 'success', "[实时状态]区域:" + zoneId + ",地址:" + addr + "(" + f_actuator_alias + `开度：${openRate}%,` + "实时状态为：" + status + ' (' + staId + ') allocate： ' + allocate, [actuatorData]);

            }

        })


    } else {
        console.log(`${new Date().toLocaleString()}`, `\x1b[30;31m ${addr.toUpperCase()}数据格式错误！！`)
    }
}
/**
 * 更新某sn卷膜最后状态
 * @param {*} sn 
 * @param {*} openRate 
 */
function updateRollerLastValue(sn: string, openRate: number, status: string, allocate: string) {
    Mysql.UpdateParamsIntoTableWhereCondition(`t_actuator`, `f_actuator_sn='${sn}'`, `f_last_value='${openRate}',f_actuator_status='${status}',f_actuator_allocate='${allocate}',f_actuator_edit_time='${moment().format('YYYY-MM-DD HH:mm:ss')}'`).then((sta) => {

    })
}

export = {
    Parser,
    SET_S100_SET_TIME_STATUS_OBJ,
    SET_S100_READ_TIME_STATUS_OBJ,
    WorkingStatusParser,
    CommonAckStatusParser
}